package controller

import (
	"encoding/json"
	"equantum/common"
	"equantum/compiler"
	"equantum/model"
	"equantum/response"
	"log"
	"os"
	"os/exec"

	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
)

type ISimulationController interface {
	Compile(ctx *gin.Context)
	Simulate(ctx *gin.Context)
}

type SimulationController struct {
	DB *gorm.DB
}

func NewSimulationController() ISimulationController {
	db := common.GetDB() // 获取数据库连接池

	return SimulationController{DB: db} // 创建controller实例
}

func (c SimulationController) Compile(ctx *gin.Context) {
	// 获取参数
	user, _ := ctx.Get("user")
	userId := user.(model.User).ID
	fileId := ctx.Params.ByName("id") // 从参数中获取

	// 读取用户userId的文件fileId
	var loadFile model.File
	if err := c.DB.Where("id = ? AND user_id = ?", fileId, userId).First(&loadFile).Error; err != nil {
		response.Fail(ctx, nil, "读取失败")
		return
	}
	fileContent := loadFile.Content

	compiler.Wg.Add(1)               // 启动一个goroutine计数器+1
	go compiler.Compile(fileContent) // 开启线程
	compiler.Wg.Wait()               // 等待线程执行完毕
	res := <-compiler.Channel        // 获取编译结果
	log.Printf("res: %v", res)
	// 返回编译结果
	if res["msg"] != nil {
		response.Fail(ctx, nil, res["msg"].(string)) // 编译失败
	} else {
		response.Success(ctx, res, "编译成功")
	}
}

func (c SimulationController) Simulate(ctx *gin.Context) {
	// 获取参数（线路抽象）
	var circuit compiler.QCircuit
	if err := ctx.BindJSON(&circuit); err != nil {
		log.Print(err)
	}
	circuitStr, err := json.Marshal(circuit) // json -> string
	if err != nil {
		response.Fail(ctx, nil, err.Error())
		return
	}

	// TODO：调用python模拟器，返回概率
	// 设置Python模拟器文件路径
	wd, err := os.Getwd()
	if err != nil {
		response.Fail(ctx, nil, err.Error())
		return
	}
	simPath := wd + "\\simulator\\equantum.py"

	// 构建Python模拟器参数
	log.Printf("circuitStr: %v", string(circuitStr))
	cmdArgs := []string{simPath, string(circuitStr)}

	// 创建命令行对象
	cmd := exec.Command("python", cmdArgs...)

	// 执行命令行并获取输出结果
	out, err := cmd.Output()
	if err != nil {
		response.Fail(ctx, nil, err.Error())
		return
	}
	log.Printf("out: %v", string(out))

	// 解析得到概率Json <e.g.> {"00": 100}
	var prob map[string]interface{}
	err = json.Unmarshal([]byte(string(out)), &prob)
	if err != nil {
		response.Fail(ctx, nil, err.Error())
		return
	}

	// 返回模拟结果
	response.Success(ctx, gin.H{"prob": prob}, "模拟成功")
	return
}
